import json
from decimal import Decimal

from django.db import transaction
from django.http import JsonResponse
from django.views import View
from django.utils import timezone
from django_redis import get_redis_connection

from goods.models import SKU
from orders.models import OrderInfo, OrderGoods
from users.models import Address

#订单结算
class OrderSettlementView(View):
    def get(self,request):
        user = request.user
        if not user.is_authenticated:
            return JsonResponse({
                'code': 400,
                'errmsg': '未登录'
            })
        addresses = Address.objects.filter(user_id=user.id,is_deleted=False)

        redis_conn = get_redis_connection('carts')
        redis_carts = redis_conn.hgetall(f'carts_{user.id}')
        redis_selected = redis_conn.smembers(f'selected_{user.id}')
        if not all([redis_carts,redis_selected]):
            return JsonResponse({
                'code':400,
                'errmsg': '未加入购物车'
            })
        address_list = []
        for address in addresses:
            address_list.append({
                'id':address.id,
                'province': address.province.name,
                'city': address.city.name,
                'district': address.district.name,
                'place': address.place,
                'mobile': address.mobile,
                'receiver': address.receiver,
            })

        sku_list = []
        for sku_id in redis_selected:
            count = int(redis_carts.get(sku_id).decode())
            sku_id = int(sku_id.decode())
            try:
                sku = SKU.objects.get(pk=sku_id)
            except SKU.DoesNotExist:
                return JsonResponse({
                    'code': 400,
                    'errmsg': '信息错误'
                })
            sku_list.append({
                'id': sku.id,
                'name': sku.name,
                'default_image_url': sku.default_image.url,
                'count': count,
                'price': sku.price
            })
        freight = Decimal(10.00)
        return JsonResponse({
            'code': 0,
            'errmsg': 'ok',
            'context':{
                'addresses':address_list,
                'skus':sku_list,
                'freight': freight
            }
        })


# 订单提交确认
class OrderCommitView(View):
    def post(self, request):
        # 提取参数
        data_dict = json.loads(request.body.decode())
        address_id = data_dict.get('address_id')
        pay_method = data_dict.get('pay_method')

        # 校验
        if not all([address_id, pay_method]):
            return JsonResponse({
                'code': 400,
                'errmsg': '缺少参数'
            })

        # 验证address_id合法性
        try:
            address = Address.objects.get(pk=address_id)
        except Exception:
            return JsonResponse({
                'code': 400,
                'errmsg': '参数address_id错误'
            })

        # 判断pay_method合法性
        if pay_method not in [
            OrderInfo.PAY_METHODS_ENUM['CASH'],
            OrderInfo.PAY_METHODS_ENUM['ALIPAY']
        ]:
            return JsonResponse({'code': 400, 'errmsg': '支付方式不支持'})

        # 获取登录用户信息
        user = request.user

        carts_dict = {}
        # 从redis读取购物车信息
        redis_conn = get_redis_connection('carts')
        redis_carts = redis_conn.hgetall('carts_%s'%user.id)
        redis_selected = redis_conn.smembers(f'selected_{user.id}')

        sku_ids = redis_carts.keys()
        for sku_id in sku_ids:
            if sku_id in redis_selected:
                carts_dict[int(sku_id)] = {
                    'count': int(redis_carts[sku_id]),
                    'selected': sku_id in redis_selected
                }
        with transaction.atomic():
            save_id = transaction.savepoint()
            # 新建订单
            order_id = timezone.localtime().strftime('%y%m%d%H%M%S') + ('%09d' % user.id)

            # 保存订单信息
            order = OrderInfo.objects.create(
                order_id = order_id,
                user = user,
                address = address,
                total_count = 0,
                total_amount = Decimal('0'),
                freight = Decimal('10.00'),
                pay_method = pay_method,
                status = OrderInfo.ORDER_STATUS_ENUM['UNPAID'] if pay_method == OrderInfo.PAY_METHODS_ENUM['ALIPAY'] else OrderInfo.ORDER_STATUS_ENUM['UNSEND']
            )

            # 新建订单商品 -- OrderGoods
            sku_selected_ids = carts_dict.keys()    # 所有已选中的商品的id
            for sku_id in sku_selected_ids:
                count = carts_dict[sku_id]['count']
                while True:
                    sku = SKU.objects.get(pk=sku_id)
                    # 获取旧数据
                    old_stock = sku.stock   # 库存
                    old_sales = sku.sales   # 销量

                    # TODO:计算新的库存和销量 乐观锁后
                    new_stock = old_stock - count
                    new_sales = old_sales + count

                    # TODO:判断库存
                    # count = carts_dict[sku_id]['count']
                    if count > old_stock:
                        transaction.savepoint_rollback(save_id)
                        return JsonResponse({
                            'code': 400,
                            'errmsg': f'{sku.name}商品库存不足'
                        })
                    # 查询sku销量与库存是否与旧的数据一致
                    result = SKU.objects.filter(pk=sku_id,stock=old_stock,sales=old_sales,is_launched=True).update(stock=new_stock,sales=new_sales)
                    if result:
                        break
                    continue

                # 新建OrderGoods对象保存到数据库
                OrderGoods.objects.create(
                    order=order,
                    sku=sku,
                    count=carts_dict[sku_id]['count'],
                    price=sku.price,
                )

                # TODO:更新数据 乐观锁之前
                # sku.stock -= count # 更新库存
                # sku.sales += count # 更新销量

                spu = sku.spu # 当前sku关联的spu
                spu.sales += count
                spu.save()

                # 更新订单的商品数量和总价格
                order.total_count += count
                order.total_amount += sku.price * count

            order.total_amount += order.freight
            order.save()
            transaction.savepoint_commit(save_id)

        # TODO:清除已经下单的购物车商品
        redis_conn.hdel('carts_%s'%user.id,*sku_selected_ids) # func(*[1,2]) --> func(1,2)
        redis_conn.srem('selected_%s'%user.id,*sku_selected_ids)

        # 构建响应
        return JsonResponse({
            'code': 0,
            'errmsg': 'ok',
            'order_id': order_id
        })

